The Input Server Table of Contents     The Input Server Index

BInputServerDevice

Derived from: none

Declared in: be/add-ons/input_server/InputServerDevice.h

Library: The Input Server

Allocation: By the Input Server only

Summary

BInputServerDevice is a base class for input devices; these are instances of BInputServerDevice subclasses that generate input events. In most cases, an input device corresponds to a device driver that handles a specific brand or model of hardware (mouse, keyboard, tablet, etc.), but it doesn't have to: an input device can get events from the Net, or generate them algorithmically, for example. Also, a single BInputServerDevice can handle more than one device driver.

BInputServerDevice objects are created and deleted by the Input Server only—you never create or delete these objects themselves.


Starting and Sending Messages

For each device that your object registers, it gets a Start() function call. This is the Input Server's way of telling your object that it can begin generating input events (for the designated device). So far, all of this—from the add-on load to the Start() call—happens within a single Input Server thread (for all input devices). When your Start() function is called, you should spawn a thread so your object can generate events without blocking the Server. Events are generated and sent through the EnqueueMessage() function.


Device Types and Control Messages

The Input Server knows about two types of devices: keyboards, and pointing devices (mice, tablets, etc). When you register your object's devices (through RegisterDevices()) you have to indicate the device type. The Input Server uses the device type to predicate the input device control messages it sends to the devices. These messages, delivered in Control() calls, tell a device that there's been a change downstream that applies specifically to that type of device. For example, when the user changes the mouse speed, each pointing device receives a B_MOUSE_SPEED_CHANGED notification.

The Be-defined control messages are predicated on device type only.

If your BInputServerDevice object manages a device other than a pointer or a keyboard, you tell the Input Server that the device is undefined. In this case, the Input Server won't send your device any device-specific messages; to send your device a message you (or an application that knows about your device) have to use a BInputDevice object.


Pointing Devices

Pointing devices such as mice, trackballs, drawing tablets, etc. generate B_MOUSE_MOVED messages (which trigger a BView>s MouseMoved() function) featuring a where field representing the cursor>s location in view co-ordinates. Unfortunately, your BInputServerDevice doesn>t know anything about views; that>s the App Server>s job. You'll still need to add this information to the B_MOUSE_MOVED messages generated by your BInputServerDevice, and the App Server will adjust it to view co-ordinates for you.

When generating a B_MOUSE_MOVED message, you add x and y fields in one of two ways:

Mice always use relative locations; tablets can use either (though they usually provide absolute values).

Relative Locations

All mice (and some drawing tablets) express the pointer location relative to its previous position. If your pointing device is operating in relative co-ordinate mode, you add x and y entries as B_INT32_TYPE values in device-defined units. The App Server interprets these units as pixels, so you may need to scale your output:

   int32 xVal, yVal;
   ...
   event->AddInt32( "x", xVal );
   event->AddInt32( "y", yVal );

Absolute Locations

Drawing tablets or other pointing devices that provide absolute locations add the x and y entries as B_FLOAT_TYPEs:

   float xVal, yVal;
   ...
   event->AddFloat( "x", xVal );
   event->AddFloat( "y", yVal );

These values must be in the range [0.0 to 1.0]. The app_server scales them to the screen>s co-ordinate system so (0.0, 0.0) is the left-top, and (1.0, 1.0) is the right-bottom of the screen. This lets the pointing device work with any screen resolution, automatically.

Now where?

When the Application Server receives one of these B_MOUSE_MOVED messages, it converts the x and y values into absolute values in the target view>s co-ordinate system, and then throws away the x and y entries in the message. Because of this, and the fact that some applications might want more accurate positional information from tablets, fill in the be:tablet_x and be:tablet_y fields as well:

   float xVal, yVal;
   ...
   event->AddFloat( "x", xVal );
   event->AddFloat( "y", yVal );
   event->AddFloat( "be:tablet_x", xVal );
   event->AddFloat( "be:tablet_y", yVal );

Other Useful Information

Pressure information is stored in the be:tablet_pressure field, as a float in the range [0.0 to 1.0] (minimum pressure to maximum pressure):

   float pressure;
   ...
   event->AddFloat( "be:tablet_pressure", pressure );

If the tablet supports tilt information, store it in be:tablet_tilt_x and be:tablet_tilt_y, scaling the information to the range [0.0 to 1.0]. A tilt of (-1.0, -1.0) tilts to the left-top, (1.0, 1.0) tilts to the right-bottom, and (0.0, 0.0) is no tilt.

   float tilt_x, tilt_y;
   ...
   event->AddFloat( "be:tablet_tilt_x", tilt_x );
   event->AddFloat( "be:tablet_tilt_y", tilt_y );

Tablets with pens that support an eraser store the eraser>s state in the be:tablet_eraser field. A value of 1 means the pen is reversed (i.e. the eraser is on), and 0 means it should behave normally.

   int32 erase_mode;
   ...
   event->AddInt32( "be:tablet_eraser", erase_mode );


Device State

The Control() protocol is designed to accommodate queries (in addition to commands). Currently, however, the Input Server maintains the keyboard and pointing device state and answers these queries itself; it doesn't forward any of the Be-defined query messages. For example, when an application asks for the current mouse speed setting (through get_mouse_speed()), the query gets no further than the Input Server itself—it doesn't get passed as a control message to a pointing device.

If you're designing a BInputServerDevice that manages a keyboard or pointing device, you must keep in mind that your device is not responsible for its "Be-defined" state. The elements of the state—mouse speed, key map, etc.—correspond to the control messages listed in "Input Device Control Messages".


Dynamic Devices

As hardware devices are attached and detached from the computer, you can add and remove items from your BInputServerDevice's list of registered devices (by calling RegisterDevice()/UnregisterDevice()). But your object has to first notice that a physical device has been added or removed. It does this by placing a node monitor on the device directory (/dev). As a convenience—and to help conserve resources—the BInputServerDevice class provides the Start/StopMonitoringDevices() functions which install and remove node monitors for you.


Creating and Registering

To create a new input device, you must:

At boot time, the Input Server loads the add-ons it finds in the input device directories. For each add-on it loads, the Server invokes instantiate_input_device() to get a pointer to the add-on's BInputServerDevice object. After constructing the object, the Server calls InitCheck() to give the add-on a chance to bail out if the constructor failed. If the add-on wants to continue, it calls RegisterDevices() (from within InitCheck()) to tell the Server which physical or virtual devices it handles.


Installing an Input Device

The input server looks for input devices in the "input_server/devices" subdirectories of B_BEOS_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, and B_USER_ADDONS_DIRECTORY.


Hook Functions


Constructor and Destructor


BInputServerDevice()

                                                         
  

BInputServerDevice(void)

Creates a new BInputServerDevice object. You can initialize your object—set initial values, spawn (but not necessarily resume; do that in Start()) threads, open drivers, etc.—either here or in the InitCheck() function, which is called immediately after the constructor.


~BInputServerDevice()

                                                         
  

~BInputServerDevice()

Deletes the BInputServerDevice object. The destructor is invoked by the Input Server only—you never delete a BInputServerDevice object from your own code. When the destructor is called, the object's devices will already be unregistered and Stop() will already have been called. If this object spawned its own threads or allocated memory on the heap, it must clean up after itself here.


Member Functions


Control()

                                                         
  

virtual status_t Control(const char *name,
      void *cookie,
      uint32 command,
      BMessage *message)

The Control() hook function is invoked by the Input Server to send an input device control message or a Node Monitor message to this object. name and cookie are the readable name and pointer-to-whatever-you-want that you used when registering the device (with the RegisterDevices() function).

 
The function's return value is ignored.


Input Device Control Messages

An input device control message is sent when a downstream change needs to be propagated to an input device. For example, when the user resets the mouse speed (through the Mouse preference), a B_MOUSE_SPEED_CHANGED control message is sent to all objects that have registered a B_POINTING_DEVICE device (see RegisterDevices()). name and cookie identify the device that this message applies to. The control message itself is represented by the command constant, optionally supplemented by message.

See "Input Device Control Messages" for a list of the control messages that the BeOS defines, and instructions for how to respond to them. An application can send a custom control message through a BInputDevice object; see BInputDevice::Control() for details.

Node Monitor Messages

A Node Monitor message is sent if an entry is added to or removed from one of the device directories that the object is monitoring, as set through StartMonitoringDevice(). In this case, name and cookie are NULL, command is B_NODE_MONITOR, and message describes the file that was added or deleted. The message's opcode field will be B_ENTRY_CREATED or B_ENTRY_REMOVED (or, potentially but nonsensically, B_ENTRY_MOVED). For instructions on how to read these messages, see "The Node Monitor" in the Storage Kit (or click on the opcode constants).


EnqueueMessage()

                                                         
  

status_t EnqueueMessage(BMessage *message)

Sends an event message to the Input Server, which passes it through the input methods and input filters before sending it to the App Server. The message you create should be appropriate for the action you're trying to depict. For example, if the user presses a key, you should create and send a B_KEY_DOWN message. A list of the system-defined event messages that an input device is expected to create and send is given in "Input Device Event Messages".

RETURN CODES

B_OK. The message was sent.


InitCheck()

                                                         
  

virtual status_t InitCheck(void)

Invoked by the Input Server immediately after the object is constructed to test the validity of the initialization. If the object is properly initialized (i.e. all required resources are located or allocated), this function should return B_OK. Start() will be invoked soon if you need to do any extra initialization. If the object returns non-B_OK, the object is deleted and the add-on is unloaded.

The default implementation returns B_OK.


RegisterDevices() , UnregisterDevices()

                                                         
  

status_t RegisterDevices(input_device_ref **devices)

status_t UnregisterDevices(input_device_ref **devices)

RegisterDevices() tells the Input Server that this object is responsible for the listed devices. This means that when a control message is sent back upstream, the message—which is tagged as being relevant for a specific device, or type of device—will be forwarded (through the Control() hook) to the responsible BInputServerDevice object(s). Typically, you initially register your devices as part of the constructor or InitCheck(). Registration is cumulative—each RegisterDevices() call adds to the object's current list of devices.

UnregisterDevices() tells the Input Server that this object is no longer responsible for the listed devices. The devices are automatically unregistered when your object is deleted.

RegisterDevices() invokes Start() for each device in the devices list; UnregisterDevices() invokes Stop().

For both functions, the devices list must be NULL-terminated, and the caller retains ownership of the list and its contents.

Note that the BeOS currently only targets the device types when sending a Control() message. For example, let's say you've registered two pointing devices and a keyboard:

   status_t MyISDevice::InitCheck()
   {
   ...
      input_device_ref **devices = 
         (input_device_ref **)malloc(sizeof(*input_device_ref * 4));
      input_device_ref mouse1 = {"Mouse 1", B_POINTING_DEVICE, 
                                 (void *)this)};
      input_device_ref mouse2 = {"Mouse 2", B_POINTING_DEVICE, 
                                 (void *)this)};
      input_device_ref keyboard = {"Keyboard", B_KEYBOARD_DEVICE, 
                                   (void *)this)};
      devices[0] = &mouse1;
      devices[1] = &mouse2;
      devices[2] = &keyboard;
      devices[3] = NULL;
      RegisterDevices(devices);
      ...
   }

When the user fiddles with the Mouse preference (more specifically, if an application calls set_mouse_speed() et. al.), this object will receive two Control() messages: one targets "Mouse 1", and the other targets "Mouse 2". That's because the mouse and keyboard functions (as defined by the BeOS and as used by the system preferences) know which type of device to control, but they don't provide a means for more granular identification. If you need a UI that identifies specific devices, you have to create the UI yourself, and use a BInputDevice object to tune the control messages that are sent back upstream.

RETURN CODES

B_OK. At least one of the devices was registered.

 
The functions don't let you un/register the same device definition twice, and RegisterDevices() won't register a device that doesn't have a name (although the name can be ""). However, the functions don't complain about violations of these conditions as long as at least one definition is properly formed.



Start() , Stop()

                                                         
  

virtual status_t Start(const char *name, void *cookie)

virtual status_t Stop(const char *name, void *cookie)

Start() is invoked by the Input Server to tell the object that it can begin sending events for the registered device identified by the arguments. The values of the arguments are taken from the input_device_ref structure you used to register the device (see RegisterDevices()). If your object needs to resume a thread (spawned in the constructor, in InitCheck(), or here), this is the place to do it.

Stop() is invoked to tell the object to stop sending events for the registered device. The device is not unregistered—you can still receive Control() messages for the device while it's stopped. You should pause or kill any threads associated with the device (that were spawned by this object) from here.

 
The return value (for both of these functions) is ignored.



StartMonitoringDevice() , StopMonitoringDevice()

                                                         
  

status_t StartMonitoringDevice(const char *deviceDir)

status_t StopMonitoringDevice(const char *deviceDir)

These are convenient covers for the Node Monitor's watch_node() and stop_watching() functions. You use them to watch for physical devices that are attached and detached, as indicated by changes to subdirectories of the system device directory (/dev).

deviceDir is the name of the device subdirectory that you want to watch. The "/dev/" root is automatically prepended; for example, if you want to watch for new ps2 mice, you would pass "input/mouse/ps2" as the deviceDir name. The Node Monitor is told to look for changes to the directory (B_WATCH_DIRECTORY opcode). When an entry is added or removed, this object receives a B_NODE_MONITOR message delivered to its Control() function.

RETURN CODES

B_OK. Success.


SystemShuttingDown()

                                                         
  

virtual status_t SystemShuttingDown(void) const

Tells the object that the Input Server is in the process of shutting down. Unless something interrupts the shutdown, this notification will be followed by a Stop() and delete, thus you don't have to do much from this function (other than note that the end is near).

 
The return value is ignored.



UnregisterDevices see RegisterDevices()


The Input Server Table of Contents     The Input Server Index


The Be Book,
...in lovely HTML...
for BeOS Release 5.

Copyright © 2000 Be, Inc. All rights reserved..